import asyncio
import threading
import time
from datetime import datetime, timedelta
from sys import platform
from typing import List, Dict, Optional

import psutil

from app.modle.models import ProcessInfo
from app.utils.util import bytes_to_mb


# class ProcessMonitor:
#     """进程监控器，用于获取系统进程信息"""
#
#     def __init__(self):
#         self.process_list= []
#
#     async def get_processes_info(self) -> List[ProcessInfo]:
#         """获取系统中所有进程的详细信息"""
#         self.process_list = []
#
#         # 获取系统中所有进程
#         for proc in psutil.process_iter(['pid', 'name', 'cpu_percent', 'memory_percent']):
#             try:
#                 # 过滤掉已终止的进程
#                 if proc.status() == psutil.STATUS_ZOMBIE:
#                     continue
#
#                 # 获取进程详细信息
#                 process_info = self._get_process_details(proc)
#                 if process_info:
#                     self.process_list.append(process_info)
#             except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
#                 # 忽略已终止或无权限访问的进程
#                 continue
#
#         # 按CPU使用率排序（降序）
#         self.process_list.sort(key=lambda p: p.cpuPercent, reverse=True)
#
#         return self.process_list
#
#     def _get_process_details(self, proc: psutil.Process) -> Optional[ProcessInfo]:
#         """获取单个进程的详细信息"""
#         try:
#             # 首次调用获取CPU百分比，需要再次调用以获取有效值
#             proc.cpu_percent(interval=None)
#
#             with proc.oneshot():  # 优化性能，一次性获取多个信息
#                 # 基本信息
#                 pid = proc.pid
#                 ppid = proc.ppid()
#                 name = proc.name()
#                 status = proc.status()
#                 threads = proc.num_threads()
#                 nice = proc.nice()
#
#                 # CPU和内存使用情况
#                 # 第二次调用，传入间隔时间获取准确值
#                 cpu_percent = proc.cpu_percent(interval=1)
#                 memory_percent = proc.memory_percent()
#                 memory_usage = proc.memory_info().rss
#
#                 # 执行路径和命令行
#                 exe_path = proc.exe()
#                 cmdline = " ".join(proc.cmdline())
#
#                 # 用户信息
#                 try:
#                     user = proc.username()
#                 except psutil.AccessDenied:
#                     user = None
#
#                 # 进程启动时间和运行时间
#                 create_time = datetime.fromtimestamp(proc.create_time())
#                 start_time = create_time.strftime("%Y-%m-%d %H:%M:%S")
#                 run_time = str(timedelta(seconds=(datetime.now() - create_time).total_seconds()))
#
#                 # 获取监听端口（需要管理员权限）
#                 try:
#                     connections = proc.connections()
#                     ports = list({conn.laddr.port for conn in connections if conn.status == 'LISTEN'})
#                 except psutil.AccessDenied:
#                     ports = []
#
#                 # 构建ProcessInfo对象
#                 return ProcessInfo(
#                     pid=pid,
#                     ppid=ppid,
#                     name=name,
#                     exePath=exe_path,
#                     status=status,
#                     user=user,
#                     cpuPercent=round(cpu_percent,1),
#                     memoryPercent=memory_percent,
#                     memoryUsage=memory_usage,
#                     startTime=start_time,
#                     runTime=run_time,
#                     threads=threads,
#                     commandLine=cmdline,
#                     nice=nice,
#                     port=ports
#                 )
#         except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
#             return None

    # def get_processes_info(self) -> List[ProcessInfo]:
    #     """使用 process_iter() 获取所有进程信息"""
    #     processes = []
    #     attrs = ['pid', 'ppid', 'name', 'exe', 'status', 'username', 'cpu_percent',
    #              'memory_percent', 'memory_info', 'create_time', 'num_threads', 'cmdline', 'nice']
    #
    #
    #     lit = psutil.process_iter(attrs=attrs)
    #     print(lit)
    #     # 使用 process_iter() 批量获取进程信息
    #     for proc in psutil.process_iter(attrs=attrs):
    #         try:
    #             p = proc.info
    #             if not p['pid']:
    #                 continue
    #
    #             # 格式化内存使用量
    #             memory_usage = self._format_memory(p['memory_info'].rss if p['memory_info'] else 0)
    #
    #             # 获取 CPU 使用率（处理首次调用问题）
    #             # cpu_percent = self._get_process_cpu_percent(p['pid'], p['cpu_percent'])
    #
    #             # 格式化启动时间和运行时间
    #             start_time = self._format_start_time(p['create_time'] if p['create_time'] else 0)
    #             run_time = self._format_run_time(p['create_time'] if p['create_time'] else 0)
    #
    #             # 获取端口信息
    #             ports = self._get_process_ports(p['pid'])
    #
    #             process_info = ProcessInfo(
    #                 pid=p['pid'],
    #                 ppid=p['ppid'] or 0,
    #                 name=p['name'] or '',
    #                 exePath=p['exe'] or '',
    #                 status=p['status'].capitalize() if p['status'] else 'Unknown',
    #                 user=p['username'] or None,
    #                 cpuPercent=round(p['cpu_percent'] or 0, 1),
    #                 memoryPercent=round(p['memory_percent'], 1) if p['memory_percent'] is not None else 0.0,
    #                 memoryUsage=memory_usage,
    #                 startTime=start_time,
    #                 runTime=run_time,
    #                 threads=p['num_threads'] or 0,
    #                 commandLine=' '.join(p['cmdline']) if p['cmdline'] else '',
    #                 nice=p['nice'] or 0,
    #                 port=ports
    #             )
    #             processes.append(process_info)
    #         except (psutil.NoSuchProcess, psutil.AccessDenied, AttributeError, TypeError):
    #             continue
    #
    #     # 按 CPU 使用率排序
    #     processes.sort(key=lambda p: p.cpuPercent, reverse=True)
    #     return processes

    # def _get_process_cpu_percent(self, pid: int, current_cpu_percent: float) -> float:
    #     """获取进程 CPU 使用率（处理首次调用返回 0 的问题）"""
    #     current_time = time.time()
    #
    #     if pid not in self.last_cpu_times:
    #         # 首次调用：使用 psutil 返回的值（可能为 0），并记录当前时间
    #         self.last_cpu_times[pid] = (current_time, current_cpu_percent)
    #         return current_cpu_percent
    #
    #     # 非首次调用：如果 psutil 返回 0，则使用我们自己的计算
    #     last_time, last_percent = self.last_cpu_times[pid]
    #     self.last_cpu_times[pid] = (current_time, current_cpu_percent)
    #
    #     # 如果 psutil 返回了有效值，直接使用
    #     if current_cpu_percent > 0:
    #         return current_cpu_percent
    #
    #     # 否则，使用上次记录的值（适用于间隔较短的情况）
    #     return last_percent

#     def _get_process_ports(self, pid: int) -> List[int]:
#         """获取进程绑定的端口"""
#         ports = []
#         try:
#             # 尝试获取进程对象
#             p = psutil.Process(pid)
#
#             # 获取 TCP 和 UDP 连接
#             for kind in ['inet', 'inet4', 'inet6']:
#                 for conn in p.connections(kind=kind):
#                     if conn.status == psutil.CONN_LISTEN and conn.laddr:
#                         ports.append(conn.laddr[1])
#
#             return list(set(ports))
#         except (psutil.NoSuchProcess, psutil.AccessDenied):
#             return []
#
#     def _format_memory(self, bytes_value: int) -> str:
#         """格式化内存使用量为带单位的字符串"""
#         units = ['B', 'KB', 'MB', 'GB']
#         unit_index = 0
#         while bytes_value >= 1024 and unit_index < len(units) - 1:
#             bytes_value /= 1024
#             unit_index += 1
#         return f"{bytes_value:.1f}{units[unit_index]}"
#
#     def _format_start_time(self, create_time: float) -> str:
#         """格式化进程启动时间"""
#         if not create_time:
#             return "Unknown"
#         return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(create_time))
#
#     def _format_run_time(self, create_time: float) -> str:
#         """计算并格式化进程运行时间"""
#         if not create_time:
#             return "Unknown"
#
#         run_time_seconds = time.time() - create_time
#         hours, remainder = divmod(int(run_time_seconds), 3600)
#         minutes, seconds = divmod(remainder, 60)
#         return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
#
#     def _calculate_mbps(self, current_bytes: int, previous_bytes: int, time_delta: float) -> float:
#         """计算 Mbps 速率"""
#         return round(((current_bytes - previous_bytes) * 8) / (time_delta * 1024 * 1024), 2)
#
#
# if __name__ == '__main__':
#     process_monitor = ProcessMonitor()
#     processes = process_monitor.get_processes_info()
#
#     print(f"共获取到 {len(processes)} 个进程")
#
#
#     for p in process_monitor:
#         if p.cpuPercent > 0:
#             print(p.model_dump_json(indent=2))


class ProcessMonitor:
    def __init__(self):
        self.process_list = []
        self.process_cache = {}  # 缓存进程对象，用于CPU百分比计算
        self.lock = threading.Lock()

    async def update_processes(self):
        """异步更新进程信息"""
        # 使用线程池执行阻塞操作，避免阻塞事件循环
        loop = asyncio.get_running_loop()
        await loop.run_in_executor(None, self._update_processes_sync)

    def _update_processes_sync(self):
        """同步更新进程信息"""
        new_process_list = []
        new_process_cache = {}

        # 首次调用，记录基准值
        for proc in psutil.process_iter(['pid', 'name']):
            try:
                # 获取或创建缓存的进程对象
                cached_proc = self.process_cache.get(proc.pid)
                if cached_proc:
                    # 使用缓存的进程对象获取CPU百分比
                    cpu_percent = cached_proc.cpu_percent(interval=None)
                    new_process_cache[proc.pid] = cached_proc
                else:
                    # 新进程，初始化并记录基准值
                    cpu_percent = proc.cpu_percent(interval=None)
                    new_process_cache[proc.pid] = proc

                # 过滤掉已终止的进程
                if proc.status() == psutil.STATUS_ZOMBIE:
                    continue

                # 获取进程详细信息
                process_info = self._get_process_details(proc, cpu_percent)
                if process_info:
                    new_process_list.append(process_info)
            except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
                continue

        # 更新进程列表和缓存
        with self.lock:
            self.process_list = new_process_list
            self.process_cache = new_process_cache

    def _get_process_details(self, proc: psutil.Process, cpu_percent: float) -> Optional[ProcessInfo]:
        """获取单个进程的详细信息"""
        try:
            with proc.oneshot():  # 优化性能，一次性获取多个信息
                # 基本信息
                pid = proc.pid
                ppid = proc.ppid()
                name = proc.name()
                status = proc.status()
                threads = proc.num_threads()
                nice = proc.nice()

                # CPU和内存使用情况
                memory_percent = proc.memory_percent()
                memory_usage = proc.memory_info().rss

                # 执行路径和命令行
                exe_path = proc.exe()
                cmdline = " ".join(proc.cmdline())

                # 用户信息
                try:
                    user = proc.username()
                except psutil.AccessDenied:
                    user = None

                # 进程启动时间和运行时间
                create_time = datetime.fromtimestamp(proc.create_time())
                start_time = create_time.strftime("%Y-%m-%d %H:%M:%S")
                run_time = str(timedelta(seconds=(datetime.now() - create_time).total_seconds()))

                # 获取监听端口（需要管理员权限）
                try:
                    connections = proc.connections()
                    ports = list({conn.laddr.port for conn in connections if conn.status == 'LISTEN'})
                except psutil.AccessDenied:
                    ports = []

                # 构建ProcessInfo对象
                return ProcessInfo(
                    pid=pid,
                    ppid=ppid,
                    name=name,
                    exePath=exe_path,
                    status=status,
                    user=user,
                    cpuPercent=round(cpu_percent, 1) if cpu_percent is not None else 0.0,
                    memoryPercent=memory_percent,
                    memoryUsage=memory_usage,
                    startTime=start_time,
                    runTime=run_time,
                    threads=threads,
                    commandLine=cmdline,
                    nice=nice,
                    port=ports
                )
        except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
            return None

    async def get_top_processes(self, limit: int = 50) -> List[ProcessInfo]:
        """获取CPU使用率最高的前N个进程"""
        with self.lock:
            # 按CPU使用率排序
            sorted_processes = sorted(self.process_list, key=lambda p: p.cpuPercent, reverse=True)
            return sorted_processes[:limit]